/*	GroundAttack class definition.
 *
*/

#include "GroundAttack.h"

// GroundAttack every minute or so
static const int GroundAttackingInterval = 24*1;

GroundAttack::GroundAttack(std::string incName) : Behavior(incName),
									lastGroundAttackFrame(-1)
{
	currentTargetBuilding = 0;
	currentTargetTile = BWAPI::TilePositions::None;
}

void GroundAttack::Enter()
{
	DEBUG_PRINT("GroundAttack(%p) entering.\n", this);
}

void GroundAttack::Execute()
{
	BWAPI::Position attackPosition(BB->GetAttackPosition().x()*TILE_SIZE,BB->GetAttackPosition().y()*TILE_SIZE);

	std::list<BWAPI::Unit*>* marines = BB->GetUnitsByTypeGeneral(BWAPI::UnitTypes::Terran_Marine);
	std::list<BWAPI::Unit*>* firebats = BB->GetUnitsByTypeGeneral(BWAPI::UnitTypes::Terran_Firebat);
	std::list<BWAPI::Unit*>* medics = BB->GetUnitsByTypeGeneral(BWAPI::UnitTypes::Terran_Medic);
	if(!marines)
	{
		control->FinishWithSuccess();
		return;
	}
	// For now, tell all non-marines. Marines will be told via their SM
	//if(marines)
	//	groundArmy.insert(groundArmy.end(), marines->begin(), marines->end());
	if(firebats)
		groundArmy.insert(groundArmy.end(), firebats->begin(), firebats->end());
	if(medics)
		groundArmy.insert(groundArmy.end(), medics->begin(), medics->end());
	BWAPI::Unit* theUnit;
	for(std::list<BWAPI::Unit*>::iterator it = groundArmy.begin(); it != groundArmy.end(); it++)
	{
		theUnit = (*it);
		BWAPI::Unit* nearestMarine = findNearestMarine(theUnit);
		BWAPI::Position targPos = (nearestMarine) ? nearestMarine->getPosition() : theUnit->getPosition(), myPos = theUnit->getPosition();

		BWAPI::Position dd = targPos-myPos;
		int d2 = dd.x()*dd.x()+dd.y()*dd.y();
		if(d2>50*50 && nearestMarine && theUnit->getType()==BWAPI::UnitTypes::Terran_Medic)
			theUnit->follow( nearestMarine, true);
		else
			theUnit->attack(attackPosition);// attackMove(attackPosition)
	}

	// setup marine micro
	std::list<MarineSM*>::iterator marineSMBegin = BB->GetMarineSMs()->begin(), marineSMEnd = BB->GetMarineSMs()->end();
	while(marineSMBegin != marineSMEnd)
	{
		MarineSM* marine = *marineSMBegin;
		marine->SetAttackTile(BWAPI::TilePosition(attackPosition));
		marineSMBegin++;
	}

	// control cleanup
	control->FinishWithSuccess();
}

void GroundAttack::Exit()
{
	DEBUG_PRINT("Exiting GroundAttack behavior.\n");
	groundArmy.clear();
}

bool GroundAttack::CheckConditions()
{
	std::list<BWAPI::Unit*>* marines = BB->GetUnitsByTypeGeneral(BWAPI::UnitTypes::Terran_Marine);
	if(marines->size() <12)
		return false;
	else
		return true;
}

BWAPI::Unit* GroundAttack::findNearestMarine(BWAPI::Unit* myVulture)
{
	std::list<BWAPI::Unit*>* marines = BB->GetUnitsByTypeGeneral(BWAPI::UnitTypes::Terran_Marine);
	BWAPI::Unit* currentBest = 0;
	BWAPI::Position myPos = myVulture->getPosition(), closePos;
	double bestDist=-1;
	for(std::list<BWAPI::Unit*>::iterator i = marines->begin(); i != marines->end(); i++)
	{
		if(!(*i) || !(*i)->exists())
			continue;
		if ((*i))
		{
			BWAPI::Position testPos = (*i)->getPosition();
			double d = testPos.getDistance(myPos);
			if(!currentBest) {
				currentBest = (*i);
				bestDist = d;
			}
			else {
				if(d<bestDist) {
					currentBest = (*i);
					bestDist = d;
				}
			}
		}
	}
	if(currentBest) {
		//BWAPI::Broodwar->sendText("Nearest enemy: %s", currentBest->getType().getName().c_str());
	}
	else {
		//BWAPI::Broodwar->sendText("No nearest enemy");
	}
	return currentBest;
}